package com.springMVC.servlet;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.springMVC.annotation.Controller;
import com.springMVC.annotation.RequestMapping;
import com.springMVC.annotation.RequestParam;
import com.springMVC.annotation.ResponseBody;
import com.springMVC.context.WebApplicationContext;
import com.springMVC.handler.MyHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author ：candy
 * @date ：Created in 2020/11/30 20:47
 * @description：
 * @version: 1.0
 */
public class DispatcherServlet extends HttpServlet {

    private WebApplicationContext webApplicationContext;

    List<MyHandler> myHandlerList = new ArrayList<>();
    private Parameter parameter;


    @Override
    public void init() {

        // 加载初始化参数 classpath:springmvc.xml
        String contextConfigLocation = this.getServletConfig().getInitParameter("contextConfigLocation");

        // 创建mvc容器
        webApplicationContext = new WebApplicationContext(contextConfigLocation);

        // 初始化
        webApplicationContext.onRefresh();

        // 初始化请求映射关系 /findUser  ====> 控制器.方法
        initHandlerMapping();
    }

    private void initHandlerMapping() {


        for (Map.Entry<String, Object> entry : webApplicationContext.iocMap.entrySet()) {
            Class<?> clazz = entry.getValue().getClass();

            if (clazz.isAnnotationPresent(Controller.class)) {
                Method[] methods = clazz.getDeclaredMethods();
                for (Method method : methods) {
                    if (method.isAnnotationPresent(RequestMapping.class)) {
                        RequestMapping annotation = method.getAnnotation(RequestMapping.class);

                        String url = annotation.value();
                        MyHandler myHandler = new MyHandler(url, entry.getValue(), method);
                        this.myHandlerList.add(myHandler);
                    }
                }
            }
        }
    }

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doDispatcher(req, resp);
    }

    private void doDispatcher(HttpServletRequest req, HttpServletResponse resp) {
        MyHandler handler = getHandler(req);
        try {
            if (handler == null) {
                resp.getWriter().println("<h1>404 not find </h1>");
            } else {
                req.getParameterMap();

                // TODO
                List<String> paramNameList = new ArrayList<>();
                Parameter[] parameters = handler.getMethod().getParameters();
                for (Parameter parameter : parameters) {
                    if (parameter.isAnnotationPresent(RequestParam.class)) {
                        paramNameList.add(parameter.getDeclaredAnnotation(RequestParam.class).value());
                    } else {
                        String name = parameter.getName();
                        paramNameList.add(name);
                    }
                }

                String[] paramResult = new String[paramNameList.size()];
                if (paramResult.length > 0) {
                    String[] params = paramNameList.toArray(new String[paramNameList.size()]);
                    paramResult[0] = req.getParameter(params[0]);
                }

                Object result = null;
                if (paramResult.length > 0) {
                    result = handler.getMethod().invoke(handler.getController(), paramResult);
                } else {
                    result = handler.getMethod().invoke(handler.getController());
                }


                if (result instanceof String) {
                    String viewName = (String) result;

                    if (viewName.contains(":")) {
                        String viewType = viewName.split(":")[0];
                        String viewPage = viewName.split(":")[1];
                        if (viewType.equals("forward")) {
                            req.getRequestDispatcher(viewPage).forward(req, resp);
                        } else if (viewType.equals("redirect")) {
                            resp.sendRedirect(viewPage);
                        }
                    } else {
                        req.getRequestDispatcher(viewName).forward(req, resp);
                    }
                } else {
                    if (handler.getMethod().isAnnotationPresent(ResponseBody.class)) {
                        ObjectMapper objectMapper = new ObjectMapper();
                        String json = objectMapper.writeValueAsString(result);

                        resp.setContentType("text/html;charset=utf-8");
                        PrintWriter writer = resp.getWriter();
                        writer.println(json);
                        writer.flush();
                        writer.close();
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public MyHandler getHandler(HttpServletRequest request) {
        String requestURI = request.getRequestURI();

        for (MyHandler myHandler : myHandlerList) {
            if (myHandler.getUrl().equals(requestURI)) {
                return myHandler;
            }
        }
        return null;
    }
}
